<?php

declare(strict_types=1);

/**
 * @Author:     Frank
 * @contact     frank_hhm@163.com
 * @Date:       2022-11-23 15:37:48
 * @Last Modified time: 2022-12-06 21:12:37
 */

namespace frank\event;

use think\Service;
use think\facade\Route;
use think\facade\Cache;
use think\facade\Request;
use think\facade\Config;
use think\facade\Middleware;
use frank\utils\helper\StringHelper;
use frank\services\annotation\AnnotationService;
use frank\services\annotation\MethodService;
use frank\services\NodeService;
use frank\exception\CommonException;

class InitRoute extends Service
{
    /**
     * 请求路径
     */
    protected $pathinfo;

    /**
     * 当前应用
     */
    protected $app;

    protected $appPath;

    protected $modulePath;

    protected $controller;

    protected $action;

    protected $route;

    protected $routePath;

    protected $class;

    public function __construct()
    {
        // 当前应用
        $this->app = config('app.default_app');
        //默认控制器
        $this->controller = config('route.default_controller');

        $this->action = config('route.default_action');
      
        $this->pathinfo = request()->pathinfo();
    }

    public function handle()
    {
        $pathinfoArray = explode('/',  $this->pathinfo);

        !empty($pathinfoArray[0]) && $this->app = $pathinfoArray[0];

        // 是否插件
        if ( !in_array($this->app, $GLOBALS['app_array']) ) {
            isset($pathinfoArray[1]) && $this->app = $pathinfoArray[1];
            isset($pathinfoArray[2]) && $this->controller = $pathinfoArray[2];
            isset($pathinfoArray[3]) && $this->action = $pathinfoArray[3];
            Request::addon($this->app);
            $this->modulePath = "addon/" . $this->app . '/' . $this->controller;
            $this->setAppPath('addon');
        } else {
            isset($pathinfoArray[1]) && $this->controller = $pathinfoArray[1];
            isset($pathinfoArray[2]) && $this->action = $pathinfoArray[2];
            $this->modulePath = "app/" . $this->app;
            $this->setAppPath('app');
        }
        if($this->app == 'sysadmin'){
             return view(app()->getRootPath() . 'public' . DS . 'sysadmin' . DS . 'index.html');
        }
        $this->routePath = $this->app .'/' . $this->controller . '/' . $this->action;

        app()->setNamespace(strtr($this->modulePath, '/', '\\'));

        request()->module($this->app);

        if(empty($this->pathinfo)) Request::setPathinfo($this->routePath);
        
        $this->setRule();

        $this->getClass();

        $this->checkMethod();

    }
    
    /**
     * 获取类
     */
    private function getClass(){

        if (strpos($this->controller,'.') !== false) {
            $arr = explode('.',$this->controller);
            $str1 =  '';
            foreach ($arr as $key => $item) {
                if(($key+1) < count($arr))
                    $str1 .= $item .'/';
                if($key+1 == count($arr))
                   $str1 .=  StringHelper::convertUnderline($item);
            }
            $classPath = "{$this->modulePath}/controller/". $str1;
        }else{
            $classPath = "{$this->modulePath}/controller/".StringHelper::convertUnderline($this->controller);
        }
        if(file_exists( root_path(). $classPath .'.php')){

            $this->class = strtr($classPath, '/', '\\');
            $this->getMethodAnnotation();
        }
        $this->setMiddleware();
    }

    /**
     * 设置应用目录
     */
    private function setAppPath($type = 'app'){
        $this->appPath = $type == 'addon' ? 'addon' . DIRECTORY_SEPARATOR . $this->app : 'app' . DIRECTORY_SEPARATOR. $this->app;
        // app()->setAppPath( $this->appPath);
        app()->setAppPath(app()->getRootPath() . $this->appPath . DIRECTORY_SEPARATOR . $this->controller . DIRECTORY_SEPARATOR);
    }

    /**
     * 设置路由
     */
    private function setRule(){
    	// dump($this->pathinfo, $this->routePath);die;
        $this->route = Route::rule($this->pathinfo, $this->routePath);
    }


    private function getMethodAnnotation(){
        $methodAnnotationSet = [];
        $methodAnnotation = new MethodService($this->class,$this->action);
        $methodAnnotation->matchAllMethodAnnotation(function (array $annotation, \ReflectionMethod $method) use (&$methodAnnotationSet) {
            if(!empty($annotation['action']) && $annotation['action'] == $this->action){
                $methodAnnotationSet = $annotation;
            }
        });
        $this->classAnnotation = $methodAnnotationSet;
    }


    /**
     * 设置中间件
     */
    private function setMiddleware(){
        $middleware = [\frank\middleware\AllowOriginMiddleware::class];

        if(!empty($this->classAnnotation['middleware'])){
            $middleware = array_merge($middleware,$this->classAnnotation['middleware']);
        }
        if(file_exists(app()->getRootPath() . $this->appPath . '/middleware/middleware.php') ){
            $appDefaultMiddleware = include app()->getRootPath() . $this->appPath . '/middleware/middleware.php';
            $middleware = array_merge($middleware,$appDefaultMiddleware);
        }
        //过滤忽略的中间件
        if(!empty($this->classAnnotation['noMiddleware']) ){
            foreach ($middleware as $key => $item) {
                if(in_array( $item , $this->classAnnotation['noMiddleware'])){
                    unset($middleware[$key]);
                }
            }
        }
        request()->annotate($this->classAnnotation);
        Middleware::import($middleware);
    }


    private function checkMethod(){
        // 检测请求方式 过滤OPTIONS 跨域问题
        if(request()->method() !== 'OPTIONS' && !empty($this->classAnnotation['method']) && !in_array(request()->method(), $this->classAnnotation['method'] )){
           die("非法请求！Not Allowed：".request()->method());exit();
        }
    }
}